﻿using System.Runtime.InteropServices;
using Win32Proxy.Api;
using Win32Proxy.Helper;
using Win32Proxy.Structs;

namespace WinCapturer
{
    public abstract class AbsCaptureHelper : ICaptureHelper
    {
        public Win32Proxy.Structs.Rectangle WindowRect => _windowRect;
        public Win32Proxy.Structs.Rectangle ClientRect => WinClientRect;
        public int BitmapDataSize => _bmpDataSize;
        public IntPtr BitmapPtr => HBitmap;
        public Win32Proxy.Structs.BitmapInfo BitmapInfo { get; } = new Win32Proxy.Structs.BitmapInfo();

        protected IntPtr HWnd = IntPtr.Zero;
        protected IntPtr HScrDc = IntPtr.Zero;
        protected IntPtr HMemDc = IntPtr.Zero;
        protected IntPtr HBitmap = IntPtr.Zero;
        protected IntPtr HOldBitmap = IntPtr.Zero;

        private Win32Proxy.Structs.Rectangle _windowRect;
        protected Win32Proxy.Structs.Rectangle WinClientRect;
        private int _bmpDataSize;

        protected abstract bool CommonInit();
        protected abstract IntPtr DoCapture();
        protected abstract bool DoCapture(out IntPtr bitsPtr);

        public bool Init(string windowName)
        {
            var handle = WindowHelper.FindWindow(null, windowName);
            if (handle.Equals(IntPtr.Zero))
            {
                return false;
            }

            return Init(handle);
        }

        public bool Init(IntPtr handle)
        {
            HWnd = handle;

            Screen screen = Screen.FromHandle(HWnd);
            //获取窗口大小
            WINDOWINFO info = new();
            info.cbSize = (uint)Marshal.SizeOf(info);
            if (!WindowHelper.GetWindowInfo(HWnd, ref info))
            {
                return false;
            }

            if (screen.Primary)
            {
                _windowRect = new Win32Proxy.Structs.Rectangle(info.rcWindow.left, info.rcWindow.top, info.rcWindow.right - info.rcWindow.left, info.rcWindow.bottom - info.rcWindow.top);
                WinClientRect = new Win32Proxy.Structs.Rectangle(info.rcClient.left, info.rcClient.top, info.rcClient.right - info.rcClient.left, info.rcClient.bottom - info.rcClient.top);
            }
            else
            {

                var scaleX = MonitorHelper.DpiX / 96;
                var scaleY = MonitorHelper.DpiY / 96;
                ////获取窗口大小
                //if (!WindowHelper.GetWindowRect(HWnd, out _windowRect)
                //    || !WindowHelper.GetClientRect(HWnd, out WinClientRect))
                //{
                //    return false;
                //}
                int left = (int)(info.rcWindow.left / scaleX);
                int top = (int)(info.rcWindow.top / scaleY);
                int right = (int)(info.rcWindow.right / scaleX);
                int bottom = (int)(info.rcWindow.bottom / scaleY);
                _windowRect = new Win32Proxy.Structs.Rectangle(left, top, right - left, bottom - top);

                left = (int)(info.rcClient.left / scaleX);
                top = (int)(info.rcClient.top / scaleY);
                right = (int)(info.rcClient.right / scaleX);
                bottom = (int)(info.rcClient.bottom / scaleY);
                WinClientRect = new Win32Proxy.Structs.Rectangle(left, top, right - left, bottom - top);
            }
            

            _bmpDataSize = WinClientRect.Width * WinClientRect.Height * 3;

            return CommonInit();
        }

        public void Cleanup()
        {
            if (HBitmap.Equals(IntPtr.Zero))
            {
                return;
            }

            //删除用过的对象
            GDI32.SelectObject(HMemDc, HOldBitmap);
            GDI32.DeleteObject(HBitmap);
            GDI32.DeleteDC(HMemDc);
            User32.ReleaseDC(HWnd, HScrDc);

            HWnd = IntPtr.Zero;
            HScrDc = IntPtr.Zero;
            HMemDc = IntPtr.Zero;
            HBitmap = IntPtr.Zero;
            HOldBitmap = IntPtr.Zero;
            //_bitsPtr = IntPtr.Zero;
        }

        public bool RefreshWindow()
        {
            return ChangeWindowHandle(HWnd);
        }

        public bool ChangeWindowHandle(string windowName)
        {
            Cleanup();
            return Init(windowName);
        }

        public bool ChangeWindowHandle(IntPtr handle)
        {
            Cleanup();
            return Init(handle);
        }

        public IntPtr Capture()
        {
            if (HBitmap.Equals(IntPtr.Zero) || HMemDc.Equals(IntPtr.Zero) || HScrDc.Equals(IntPtr.Zero))
            {
                return IntPtr.Zero;
            }

            return DoCapture();
        }

        public bool Capture(out IntPtr bitsPtr, out int bufferSize, out Win32Proxy.Structs.Rectangle rect)
        {
            bitsPtr = IntPtr.Zero;
            bufferSize = _bmpDataSize;
            rect = WinClientRect;

            if (HBitmap.Equals(IntPtr.Zero) || HMemDc.Equals(IntPtr.Zero) || HScrDc.Equals(IntPtr.Zero))
            {
                return false;
            }

            return DoCapture(out bitsPtr);
        }
    }
}
